<?php
/**
 * Nordic Repository
 * 
 * LICENSE
 * 
 * The new BSD license is applied on this source-file. For further
 * information please visit http://license.nordic-dev.de/newbsd.txt
 * or send an email to andre.moelle@gmail.com.
 */

/**
 * This class is for useful methods which do not belong to any other
 * classes.
 * 
 * @category   Nordic
 * @package    Nordic_Util
 * @copyright  2007 Nordic Development
 * @license    http://license.nordic-dev.de/newbsd.txt (New-BSD license)
 * @author     Andre Moelle <andre.moelle@gmail.com>
 * @version    $Id: Util.php 3 2007-07-08 09:21:42Z andre.moelle $
 */
class Nordic_Util
{
	/**
	 * Compares two array with each other.
	 * 
	 * Only if these two are equal true is returned. It checks
	 * whether both arrays share the same keys with the same content.
	 * The order does not matter if using associative keys.
	 * 
	 * @param Array $arr first array to check
	 * @param Array $arr2 second array to check
	 * @return Boolean
	 */
	public static function compareArray ($arr, $arr2)
	{
		if(count($arr) != count($arr2))
		{
			return false;
		}
		
		return (!count(array_diff_assoc($arr, $arr2)));
	}
	
	/**
	 * Returns the file-extension.
	 * 
	 * @param String $path path to file
	 * @return String
	 */
	public static function getExtension ($path)
	{
		$file = basename($path);
		
		if(!$file)
		{
			return '';
		}
		
		if($file[0] == '.')
		{
			$file = substr($file, 1);
		}
		
		$pos = strrpos($file, '.');
		
		if($pos === false)
		{
			return '';
		}
		
		return substr($file, $pos + 1);
	}
	
	/**
	 * This method shortens a string to a specified length.
	 * 
	 * It is XHTML-aware, i.e. no tags will get broken. Additionally, these
	 * tags do not count to the specified length. Since this method is for
	 * cutting dynamic strings, this method does not consider comments.
	 * Furthermore you can assign an optional ending which is added to the shortened
	 * string before the tags get closed.
	 * 
	 * @param string $string string containing XHTML
	 * @param integer $length maximum length of the string (without tags) but with whitespaces
	 * @param string $ending optional parameter which is appended before closing the tags
	 * @return shortened string
	 */
	public static function shortenXHTML ($string, $length, $ending = '')
	{
		if(strlen(strip_tags($string)) < $length)
		{
			return $string;
		}
		
		$tags = array();
		$pos = 0;
		$result = '';
		
		do
		{
			if(($tagStart = strpos($string, '<', $pos)) === false)
			{
				$result .= substr($string, $pos, $length);
				break;
			}
			
			$tagEnd = strpos($string, '>', $tagStart);
			$length -= $tagStart - $pos;
			
			if($length >= 0)
			{
				// closing tags remove tags from the tags-array
				if($string[$tagStart + 1] == '/')
				{
					$tag = substr($string, $tagStart + 2, $tagEnd - $tagStart - 2);
					
					$id = array_search($tag, $tags);
					
					if($id !== false)
					{
						unset($tags[$id]);
					}
				}
				// this is no standalone tag - we add the tag to the array
				else if(substr($string, $tagEnd -1, 1) != '/')
				{
					$spacePos = strpos($string, ' ', $tagStart);
					
					// this tag has no attributes
					if($spacePos === false || $spacePos > $tagEnd)
					{
						$tag = substr($string, $tagStart + 1, $tagEnd - $tagStart - 1);
					}
					// it has attributes
					else
					{
						$tag = substr($string, $tagStart + 1, $spacePos - $tagStart - 1);
					}
					
					array_unshift($tags, $tag);
				}
			}
			
			if($length < 0)
			{
				$result .= substr($string, $pos, $tagStart - $pos + $length);
			}
			else
			{
				$result .= substr($string, $pos, $tagEnd - $pos + 1);
			}
			
			$pos = $tagEnd + 1;
		}
		while($length > 0);
		
		$result .= $ending;
		
		foreach($tags as $tag)
		{
			$result .= '</' . $tag . '>';
		}
		
		return $result;
	}
	
	/**
	 * An improved version of the wordwrap-function.
	 * 
	 * The difference between this method and the wordwrap function
	 * is the behaviour with strings larger than allowed. If a string
	 * is larger the string is cut off immediately. So there is no
	 * extra break like in the original function.
	 * 
	 * @param String $string string to wrap
	 * @param Integer $length biggest possible length
	 * @param String $break string that is used as break
	 * @return String
	 */
	public static function wrap ($string, $length = 75, $break = "<br />\n")
	{
		$result = '';
		$len = $length;
		
		foreach(explode(' ', $string) as $item)
		{
			$strlen = strlen($item);
			
			if($strlen <= $length)
			{
				if($strlen > $len)
				{
					$result .= $break;
					$len = $length;
				}
				
				$result .= $item;
				$len -= $strlen;
			}
			else
			{
				while($strlen > 0)
				{
					if($strlen > $len)
					{
						$result .= substr($item, 0, $len) . $break;
						$item = substr($item, $len);
						$strlen -= $len;
						$len = $length;
					}
					else
					{
						$result .= $item;
						$len -= $strlen;
						$strlen = 0;
					}
				}
			}
		}
		
		return $result;
	}
	
	/**
	 * Writes content to a specified path.
	 * 
	 * The special of this method is that it checks if the path
	 * exists. If some directories does not exist, they will be
	 * created. This solves some problems with non-existing
	 * directories. Result is the amount of bytes written.
	 * 
	 * @param String $path path to write
	 * @param String $content content to write
	 * @return Integer
	 */
	public static function write ($path, $content)
	{
		$temp = array();
		$dir = dirname($path);
		
		while(!file_exists($dir))
		{
			$temp[] = $dir;
			
			$dir = dirname($dir);
		}
		
		foreach(array_reverse($temp) as $dir)
		{
			mkdir($dir);
		}
		
		return file_put_contents($path, $content);
	}
}